package cn.kailangtu.modbus;


import android.util.Log;

import org.greenrobot.eventbus.EventBus;

import cn.kailangtu.commonevents.eventEntity.WriteDataToMachineEvent;
import cn.kailangtu.commontools.CommonUtils;

public class ModbusSlave {

    //byte[][] store = new byte[10000][2];
    static byte[] store = new byte[20000];


    public static void setTestData(){
        store[19] = 15;
    }

    public static byte[] execute(byte[] command)
    {
        ModbusCommand cmd = ModbusCommand.buildCommand(command);

        if(cmd != null){
            Log.d("MODBUS","数据正常");
            switch(cmd.getFunction())
            {

                case 0x03:
                    //读单个寄存器
                    return read_03(cmd);

                case 0x06:
                    //写单个寄存器
                    return read_06(cmd);

                case 0x10:
                    //写多个寄存器
                    return read_10(cmd);
            }
        }
        else {
            Log.d("MODBUS","数据不正常");
        }

        return null;
    }

    public static byte[] execute(String command)
    {


        ModbusCommand cmd = ModbusCommand.buildCommand(command);

        if(cmd != null){
            Log.d("MODBUS","数据正常");
            switch(cmd.getFunction())
            {

                case 0x03:
                    //读单个寄存器
                    return read_03(cmd);

                case 0x06:
                    //写单个寄存器
                    return read_06(cmd);

                case 0x10:
                    //写多个寄存器
                    return read_10(cmd);
            }
        }
        else {
            Log.d("MODBUS","数据不正常");
        }

        return null;
    }

    public static byte[] executeTcp(byte[] command)
    {


        ModbusCommandTcp cmd = ModbusCommandTcp.buildCommand(command);
        byte[] result = null;
        if(cmd != null){
            Log.d("MODBUS","数据正常");
            switch(cmd.getFunction())
            {

                case 0x03:
                case 0x04:
                    //读单个寄存器
                    return read_03_tcp(cmd);

                case 0x06:
                    //写单个寄存器
                    result =  read_06_tcp(cmd);
                    processLogData();
                    return result;

                case 0x10:
                    //写多个寄存器
                    result =  read_10_tcp(cmd);
                    processLogData();
                    return result;
            }
        }
        else {
            Log.d("MODBUS","数据不正常");
        }

        return null;
    }

    public static byte[] executeTcp(String command)
    {


        ModbusCommandTcp cmd = ModbusCommandTcp.buildCommand(command);

        if(cmd != null){
            Log.d("MODBUS","数据正常");
            switch(cmd.getFunction())
            {

                case 0x03:
                case 0x04:
                    //读单个寄存器
                    return read_03_tcp(cmd);

                case 0x06:
                    //写单个寄存器
                    return read_06_tcp(cmd);

                case 0x10:
                    //写多个寄存器
                    return read_10_tcp(cmd);
            }
        }
        else {
            Log.d("MODBUS","数据不正常");
        }

        return null;
    }


    public static byte[] read_03_tcp(ModbusCommandTcp cmd)
    {
        int intStore = CommonUtils.byteArrayToInt16( cmd.getStartStore());
        int intLength = CommonUtils.byteArrayToInt16(cmd.getStoreCount());

        Log.d("MODBUS","store:"+intStore+ " | "+intLength);

        if( intStore   <= 9700 & intLength < 128) {
            byte[] data = new byte[intLength * 2];


            System.arraycopy(store, intStore * 2, data, 0, intLength * 2);

            return cmd.receive(data);
        }
        return null;
    }

    public static byte[] read_06_tcp(ModbusCommandTcp cmd){
        int intStore = CommonUtils.byteArrayToInt16( cmd.getStartStore());
        Log.d("MODBUS","STORE:"+intStore);
        Log.d("MODBUS","DATA:"+CommonUtils.ByteArrayToHexString(cmd.getData()));
        if( intStore   <= 9700 & cmd.getData().length < 256) {
            System.arraycopy(cmd.getData(), 0, store, intStore * 2, cmd.getData().length);

            EventBus.getDefault().post(new WriteDataToMachineEvent(1, intStore, CommonUtils.byteArrayToInt16(cmd.getData())));
            return cmd.receive(cmd.getData());
        }
        return null;
    }

    public static byte[] read_10_tcp(ModbusCommandTcp cmd){
        int intStore = CommonUtils.byteArrayToInt16( cmd.getStartStore());


        Log.d("MODBUS","DATA:"+CommonUtils.ByteArrayToHexString(cmd.getData())+" ||| LENGTH:"+cmd.getData().length);

        if( intStore   <= 9700 & cmd.getData().length < 256) {
            System.arraycopy(cmd.getData(), 0, store, intStore * 2, cmd.getData().length);

            return cmd.receive(null);
        }
        return null;
    }

    public static byte[] read_10(ModbusCommand cmd){
        int checkValue = check(cmd);
        if(checkValue == 0)
        {
            int intStore = CommonUtils.byteArrayToInt16( cmd.getStore());

            System.arraycopy(cmd.getData(), 3, store, intStore*2, cmd.getData().length-3);

            byte[] receiveData = new byte[4];
            System.arraycopy(cmd.getStore(),0,receiveData,0,cmd.getStore().length);
            System.arraycopy(cmd.getData(),0,receiveData,cmd.getStore().length,2);
            return cmd.receive(receiveData);
        }
        else {
            return cmd.errData(checkValue);
        }
    }

    public static byte[] read_06(ModbusCommand cmd)
    {
        int checkValue = check(cmd);
        if(checkValue == 0)
        {
            int intStore = CommonUtils.byteArrayToInt16( cmd.getStore());

            System.arraycopy(cmd.getData(), 0, store, intStore*2, cmd.getData().length);

            byte[] receiveData = new byte[cmd.getStore().length+ cmd.getData().length];
            System.arraycopy(cmd.getStore(),0,receiveData,0,cmd.getStore().length);
            System.arraycopy(cmd.getData(),0,receiveData,cmd.getStore().length,cmd.getData().length);
            return cmd.receive(receiveData);
        }
        else {
            return cmd.errData(checkValue);
        }
    }

    public static byte[] read_03(ModbusCommand cmd)
    {
        int checkValue = check(cmd);
        if(checkValue == 0)
        {
            int intStore = CommonUtils.byteArrayToInt16( cmd.getStore());
            int intLength = CommonUtils.byteArrayToInt16(cmd.getData());


            byte[] data = new byte[intLength*2+1];
            data[0] = (byte)(intLength * 2);


            System.arraycopy(store, intStore *2, data, 1, intLength*2);

            return cmd.receive(data);
        }
        else {
            return cmd.errData(checkValue);
        }

    }

    private static int check(ModbusCommand cmd)
    {
        int result = 0;
        switch(cmd.function)
        {
            case 0x03:
            case 0x01:
            case 0x02:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x0f:
            case 0x10:
              int store = CommonUtils.byteArrayToInt16(cmd.getStore());
              if(store < 0 || store > 9999)
              {
                  result = 2;
              }



              break;
            default:
                result = 1;
                break;
        }
        if(cmd.getFunction() == 0x10)
        {
            if((cmd.getData()[2] &0xFF)> 127)
            {
                result = 3;
            }
        }


        return result;
    }



    /*
    Modbus回复错误格式通常包括以下几个部分：
    ‌设备地址‌：用来标识消息的目标设备（或从设备的响应来源），通常是一个字节。
    ‌错误功能码‌：当Modbus设备接收到不能处理的请求或请求无效时，它会返回一个错误响应。错误响应的功能码是原请求的功能码加上80（十六进制）。例如，如果请求的功能码是03（读保持寄存器），则错误响应的功能码将是83。
    ‌异常码‌：说明错误的类型。例如，0x01表示非法功能，0x02表示非法数据地址，0x03表示非法数据值，等等。
    ‌CRC校验和‌：在RTU模式下，每条消息的末尾包括两个字节的循环冗余校验（CRC）校验和，用于错误检测。
    具体的错误回复格式可能如下所示：
     */

    private  static void processLogData() {

        int index = 6001 * 2;
        int readLogValue = CommonUtils.byteArrayToInt16(new byte[]{store[index], store[index + 1]});
        if (readLogValue == 1) {
            System.arraycopy(SpecialData.exceptionLog,0,store,12000,SpecialData.exceptionLog.length);
        }
    }

    public static void processNewData(int startAddress,byte[] data)
    {
        if(startAddress < 6000 && data != null)
        {
            System.arraycopy(data,3,store,startAddress * 2,data.length-5);
        }
    }

    static boolean inited= false;

    public static boolean isInited() {
        return inited;
    }

    public static void setInited(boolean inited) {
        ModbusSlave.inited = inited;
    }
}
